// system libs
var sys = require('sys');
var http = require('http');
var fs = require("fs");
var path = require('path');
var querystring = require('querystring');
var url = require("url");
var crypto = require('crypto');

// custom libs
var mongo = require('./lib/mongodb');
var io = require('./lib/socket.io');

var host = process.env['MONGO_NODE_DRIVER_HOST'] != null ? process.env['MONGO_NODE_DRIVER_HOST'] : 'localhost';
var port = process.env['MONGO_NODE_DRIVER_PORT'] != null ? process.env['MONGO_NODE_DRIVER_PORT'] : mongo.Connection.DEFAULT_PORT;
var db = new mongo.Db('knattertron', new mongo.Server(host, port, {}), {});
var host = "http://192.168.2.89:8080/";

// Knattertron libs
var cookies = require('./cookies');
var playerPool = require('./playerpool').create();
var gamePool = require('./gamepool').create();
var queuePool = require('./queuepool').create(playerPool, gamePool);
var player = require('./player');

// Array Remove - By John Resig (MIT Licensed)
Array.prototype.remove = function(from, to) {
  var rest = this.slice((to || from) + 1 || this.length);
  this.length = from < 0 ? this.length + from : from;
  return this.push.apply(this, rest);
};

// HTTP Server
var httpServer = http.createServer(function (req, res) {
  res.myHeaders = {
    'Content-Type': 'text/html'
  };
  
  var reqUrl = url.parse(req.url, true);
  // /login/check
  //  Handle requests that want to check if a playername is registered
  if(reqUrl.pathname == "/login/check" && req.method == "GET") {
    var getParams = querystring.parse(reqUrl.pathname);
    
    var nameExistsCallback = function(err, docu)
    {
      dbError(err);
      
      if(docu)
      {
        res.writeHead(200, {'Content-Type': 'text/json'});    
        res.write(JSON.stringify({exists: true}));
        res.end();
      }
      else
      {
        res.writeHead(200, {'Content-Type': 'text/json'});    
        res.write("aa");
        res.end();
      }
    }
      
    db.collection("players", function(err, collection) { 
      dbError(err) || collection.findOne({"playername": reqUrl.query.playername || ""}, nameExistsCallback);
    });
  }
  // login
  //  Handle login requests
  else if(reqUrl.pathname == "/login" && req.method == "POST") {
    var data = "";
    req.on('data', function (chunk) {
      data += chunk;
    });
    req.on('end', function () {
      // We got all data, 

      var errors = [];
      
      var loginData = querystring.parse(data);
      if(!loginData['playername'] || loginData['playerName'] < 4)
          errors.push("The player name you choose is to short.");
          
      // A callback
      var isRegisteredCallback = function(err, docu) {
        dbError(err);
        
        if(docu) {
          // Validate the password input
          if(!loginData['password'] || loginData['password'] < 6)
            errors.push("The password you entered is missing or to short.");
            
          // Authenticate is aswell
          var hash = crypto.createHash("sha1");
          hash.update(loginData['password']);
          var digest  = hash.digest("hex");
          if(digest != docu.password)
            errors.push("The password you entered does not belong to the chosen player name");
        }
      
        if(errors.length) {
          var msg = "";
          for(var i in errors)
            msg += errors[i] + "\n";
            
          res.writeHead(200, {'Content-Type': 'text/json'});    
          res.write(JSON.stringify({error: true, message: msg}));
          res.end();    
        }
        else {
          // Data validatted and authenticated
          // If this isn't a guest login, we generate a session for the player
          var newPlayer = player.create(loginData['playername']);
          playerPool.add(newPlayer);
          queuePool.newPlayerInPool(newPlayer);
          cookies.Set(res, "id", newPlayer.id);
          
          sys.log("Validation and authentication completed for " + loginData['playername'] + ":" + loginData['password']);          
          
          res.myHeaders['Content-Type'] = 'text/json';
          res.writeHead(200, res.myHeaders);    
          res.write(JSON.stringify({success: true}));
          res.end();
        }
      }
                
      // Check if it's a registered playername, if it is we also validate the password
      db.collection("players", function(err, collection) { 
        dbError(err) || collection.findOne({"playername": loginData['playername']}, isRegisteredCallback);
      });
    });
  }
  // queue
  //  Handle queue pages
  else if(reqUrl.pathname == "/queue.html") {
    var id = cookies.Get(req, "id")
    
    // Make sure the id cookie is set
    if(!id)
    {
      res.writeHead(300, {'Location': host + 'login.html'});
      res.end();      
      return;
    }
    
    fs.readFile("../client" + reqUrl.pathname, function(err, data) {
      res.writeHead(200, {'Content-Type': 'text/html'});
      res.write(data);
      res.end();
    });
  }
  // status
  //  Return the status code of additional information about the phase the player resides in
  else if(reqUrl.pathname == "/status") {  
    var id = cookies.Get(req, "id")
    
    // Make sure the id cookie is set
    // And make sure the id is known in the playerpool
    if(!id)
    {
      res.writeHead(200, {'Content-Type': 'text/json'});    
      res.write(JSON.stringify({error: true, message: "Missing id cookie"}));
      res.end();     
      return;
    }
    
    // Todo: Move this somewhere sane
    var status = -1;
    var data = {};
    if(playerPool.contains(id))
      status = 1
    else if(queuePool.contains(id)) {
      var queue = queuePool.get(id);
      data.queueList = queue.playerList;
      
      if(!queue.full())
        status = 2;
      else if(queue.inCountdown)
      {
        status = 3;
        data.countdown = queue.countdown;
      }
    }
    else if(gamePool.contains(id)) {
      var game = gamePool.get(id);
      if(game.inCountdown())
        status = 4;
      else if(!game.isFinished())
        status = 5;
      else if(game.isFinished())
        status = 6;
      else if(game.onScore())
        status = 7;
    }
    else {
      sys.log("Unable to determine status");
    }
    
    if(status != -1)
    {
      res.writeHead(200, {'Content-Type': 'text/json'});    
      res.write(JSON.stringify({
        success: true,
        "status": status,
        "data": data
      }));
      res.end();     
      return;
    }
    else
    {
      res.writeHead(200, {'Content-Type': 'text/json'});    
      res.write(JSON.stringify({error: true, message: "Failed to resolve status code"}));
      res.end();     
      return;
    }
  }
  // game
  //  Handle game pages
  else if(reqUrl.pathname == "/game.html") {
    var id = cookies.Get(req, "id")
    
    // Make sure the id cookie is set
    if(!id)
    {
      res.writeHead(300, {'Location': host + 'login.html'});
      res.end();      
      return;
    }
    
    fs.readFile("../client" + reqUrl.pathname, function(err, data) {
      res.writeHead(200, {'Content-Type': 'text/html'});
      res.write(data);
      res.end();
    });
  }
  else if(reqUrl.pathname.length > 1) {    
    // Supply correct MIME-type
    var ext = path.extname(reqUrl.pathname);
    switch(ext)
    {
      case ".css":
        res.writeHead(200, {'Content-Type': 'text/css'});
        break;
      case ".js":
        res.writeHead(200, {'Content-Type': 'text/javascript'});
        break;
      default:
        res.writeHead(200, {'Content-Type': 'text/html'});
        break;
    }

    fs.readFile("../client" + reqUrl.pathname, function(err, data) {
      if(err)
      {
        res.write("Failed to find " + reqUrl.pathname + " (Absolute path: ../client" + reqUrl.pathname + ")");
        res.end();
        return;
      }
      res.write(data);
      res.end();
    });
  }
  // If no path names is specified, we return the login page
  else {
    res.writeHead(200, {'Content-Type': 'text/html'});    
    fs.readFile("../client/login.html", function(err, data) {
      res.write(data);
      res.end();
    });
  }
});

function dbError(err) {
  if(err) {
    sys.puts("Database error occured: " + err);
    return true;
  }
  else
    return false;
}1

// Start the server
httpServer.listen(8080);
sys.log('HTTP Server running at port 8080');
sys.log('Enter a command: (quit to stop)');

// Start the socket server
var io = io.listen(server);
var buffer = [];

io.on('connection', function(client){
	client.send({ buffer: buffer });
	client.broadcast({ announcement: client.sessionId + ' connected' });

	client.on('message', function(message){
		var msg = { message: [client.sessionId, message] };
		buffer.push(msg);
		if (buffer.length > 15) buffer.shift();
		client.broadcast(msg);
	});

	client.on('disconnect', function(){
		client.broadcast({ announcement: client.sessionId + ' disconnected' });
	});
});

// Listen vor input
var stdin = process.openStdin();
stdin.on('data', function (chunk) {
  if(chunk == 'quit\n') {
    httpServer.close();
    process.exit();
  }    
});

db.open(function(err, db) {
  /*db.dropDatabase(function(err, result) {
    db.collection('test', function(err, collection) {
      // Erase all records from the collection, if any
      collection.remove(function(err, collection) {
        // Insert 3 records
        for(var i = 0; i < 3; i++) {
          collection.insert({'a':i});
        }
        
        collection.count(function(err, count) {
          sys.puts("There are " + count + " records in the test collection. Here they are:");

          collection.find(function(err, cursor) {
            cursor.each(function(err, item) {
              if(item != null) {
                sys.puts(sys.inspect(item));
                sys.puts("created at " + new Date(item._id.generationTime) + "\n")
              }
              // Null signifies end of iterator
              if(item == null) {                
                // Destory the collection
                //collection.drop(function(err, collection) {
                //  db.close();
                //});
              }
            });
          });          
        });
      });      
    });
  });*/
});